package com.mxpio.erp.purchase.policy.impl;


import com.mxpio.erp.common.LotStatusUtil;
import com.mxpio.erp.common.enums.NoticeStatusEnums;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.inventory.entity.Lot;
import com.mxpio.erp.common.jpa.model.LotKey;
import com.mxpio.erp.common.jpa.model.Notice;
import com.mxpio.erp.common.jpa.model.NoticeLine;
import com.mxpio.erp.common.jpa.model.Order;
import com.mxpio.erp.common.order.policy.AbstractBizOrderPolicy;
import com.mxpio.erp.common.order.policy.OrderContext;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.purchase.entity.*;
import com.mxpio.erp.common.quality.entity.InQualityOrder;
import com.mxpio.erp.common.quality.entity.InQualityOrderLine;
import com.mxpio.erp.common.technology.entity.Item;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpio.erp.common.vo.OrderExcuteLineVo;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.security.util.SecurityUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 采购订单退货执行策略
 * @author fangsong
 *
 */
public class DefaultRejectPolicy extends AbstractBizOrderPolicy {

	private List<OrderExcuteLineVo> orderExcuteVos;

	private OrderLineService orderLineService;
	public DefaultRejectPolicy(List<OrderExcuteLineVo> orderExcuteVos,OrderLineService orderLineService) {
		this.orderExcuteVos = orderExcuteVos;
		this.orderLineService = orderLineService;//增加入参
	}

	@Override
	public void execute(OrderContext context) {
	}

	//重写执行逻辑， 根据提交数据的批次状态，分别生成对应的合格品退货、不合格品退货
	@Override
	public void apply(OrderContext context) {
		if(beforeExecute(context)) {
			execute(context);
			Order order = context.getEntity();
			List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();

			Map<String, RejectNotice> noticeMap = new HashMap<>();
			Map<String,List<OrderExcuteLineVo>> voMap = new HashMap<>();
			for(OrderExcuteLineVo orderExcuteVo : orderExcuteVos) {
				LotKey lotKey = new LotKey();
				lotKey.setLotNo(orderExcuteVo.getLotNo());
				lotKey.setSubLotIndex(orderExcuteVo.getSubLotIndex());
				Lot lot = JpaUtil.getOne(Lot.class, lotKey);
				String rejectType = "";//值对应通知单退货类型字典值
				if (StringUtils.equals(lot.getLotStatus(), LotStatusUtil.toBinaryString("0"))){
					rejectType = "0";//合格品退货
				}else{
					rejectType = "1";//不合格品退货
				}

				RejectNotice notice = noticeMap.get(orderExcuteVo.getWhCode() + "#" +rejectType);
				if(notice == null) {//20221123 wpp 下边判断增加accessType条件，out类型的操作不需要生成QualityClass检验单
					notice = new RejectNotice();
					notice.setBizOrderNo(order.getBizNo());
					notice.setNoticeDate(new Date());
					notice.setWhCode(orderExcuteVo.getWhCode());
					notice.setAccessType(OrderEnums.AccessType.OUT.getCode());
					notice.setPickingType(context.getPickingType());
					notice.setRejectType(rejectType);
					notice.setNoticeStatus(NoticeStatusEnums.NoticeStatus.CREATE.getStatusCode());
					noticeMap.put(orderExcuteVo.getWhCode() + "#" +rejectType, notice);
					voMap.put(orderExcuteVo.getWhCode() + "#" +rejectType, new ArrayList<OrderExcuteLineVo>());
				}
				voMap.get(orderExcuteVo.getWhCode() + "#" +rejectType).add(orderExcuteVo);
			}
			// 生成通知单明细
			for(Map.Entry<String,RejectNotice> entry : noticeMap.entrySet()) {
				Notice notice = entry.getValue();
				JpaUtil.save(notice);
				int lineNo = 0;
				for(OrderExcuteLineVo vo : voMap.get(entry.getKey())) {
					lineNo++;
					NoticeLine line = notice.createLine(vo);
					line.setLineNo(lineNo+"");
					Item item = JpaUtil.linq(Item.class).idEqual(vo.getItemCode()).findOne();
					line.setItemName(item.getItemName());
					line.setItemSpec(item.getItemSpec());
					line.setUnitCode(item.getUnitCode());
					line.setDrawingNo(item.getDrawingNo());
					JpaUtil.save(line);
				}
			}
			if(OrderStatusEnums.OrderStatus.PLAN.getStatusCode().equals(order.getOrderStatus())||
					OrderStatusEnums.OrderStatus.ORDERED.getStatusCode().equals(order.getOrderStatus())){
				order.setOrderStatus(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode());
				order.setExecuteTime(new Date());
				order.setExecutor(SecurityUtils.getLoginUsername());
				JpaUtil.update(order);
			}
			afterExecute(context);
		} else {
			if(CollectionUtils.isEmpty(context.getErrors())) {
				context.addError("前置校验不通过");
			}
		}
	}

	@Override
	public OrderContext config(OrderContext context) {
		context.setOrderExcuteVos(orderExcuteVos);
		context.setNoticeClass(RejectNotice.class);
		context.setAccessType(OrderEnums.AccessType.OUT.getCode());
		context.setPickingType(NoticeStatusEnums.NoticeType.PO_OUT.getCode());
		return context;
	}

	@Override
	public boolean beforeExecute(OrderContext context) {
		//此处写生产订单执行前置校验逻辑
		Order order = context.getEntity();
		if (order instanceof PurchaseOrder && context.getOrderExcuteVos().size()>0){
			List<OrderExcuteLineVo> orderExcuteVos = context.getOrderExcuteVos();
			List<String> orderlinesStr = orderExcuteVos.stream().map(OrderExcuteLineVo::getBizOrderlineNo).collect(Collectors.toList());
			List<PurchaseOrderLine> orderLines = JpaUtil.linq(PurchaseOrderLine.class).equal("bizNo", order.getBizNo()).in("lineNo", orderlinesStr).list();
			NoticeClassVo receivingNoticeClazz = new NoticeClassVo(ReceivingNotice.class, ReceivingNoticeLine.class);
			NoticeClassVo rejectNoticeClazz = new NoticeClassVo(RejectNotice.class, RejectNoticeLine.class);
			NoticeClassVo inQualityOrderClazz = new NoticeClassVo(InQualityOrder.class, InQualityOrderLine.class);//增加入库验收单 数据统计
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(receivingNoticeClazz);
			noticeClassVos.add(rejectNoticeClazz);
			noticeClassVos.add(inQualityOrderClazz);
			orderLineService.handleBizOrderLineQuantity(orderLines, noticeClassVos, OrderEnums.AccessType.IN.getCode());
			Map<String, PurchaseOrderLine> orderLineMap = JpaUtil.index(orderLines,"lineNo");
			for(OrderExcuteLineVo orderExcuteVo : orderExcuteVos) {
				// BigDecimal lineQuantity = orderExcuteVo.getLineQuantity();
				BigDecimal quantity = orderExcuteVo.getQuantity();
				String bizOrderlineNo = orderExcuteVo.getBizOrderlineNo();
				PurchaseOrderLine orderLine = orderLineMap.get(bizOrderlineNo);
				if (orderLine!=null){
					BigDecimal actualQuantity = orderLine.getActualQuantity();
					BigDecimal actualRejectQuantity = orderLine.getActualRejectQuantity();
					//BigDecimal planQuantity = orderLine.getPlanQuantity();
					BigDecimal planRejectQuantity = orderLine.getPlanRejectQuantity();
					//退货时，最大可退数量=已执行数量减去已执行退货数量减去计划退货数量，不考虑计划执行数量
					BigDecimal lastMax = actualQuantity.subtract(actualRejectQuantity).subtract(planRejectQuantity);
					//原执行行总数量 减去
					if (quantity.compareTo(lastMax)>0){
						context.addError("提交数据中行号【"+bizOrderlineNo+"】执行数量大于最大可执行数量【"+lastMax+"】。");
						return false;
					}
				}
			}
		}
		return true;
	}

	@Override
	public void afterExecute(OrderContext context) {
		//更新状态
		Order order = context.getEntity();
		if(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode().equals(order.getOrderStatus())) {//执行退货操作时，如果订单状态是完成，则需要更新为执行中。
			order.setOrderStatus(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode());
			//order.setExecuteTime(new Date());
			JpaUtil.update(order);
		}
	}

}
